"""
提供一些高阶函数技巧。

父类调用注册
当子类覆写了父类方法后，在调用子类方法时自动调用其父类方法。
用法：
class Parent(MustCall):
    @mustcall
    def f(self):
        print("parent call f")


class Child(Parent):
    def f(self):
        print(f"child's f says:")


p: Parent = Parent()
p.f()
p: Parent = Child()
p.f()

设计思路

在新建类实例时，为子类方法添加装饰。因此任务拆解为对子类实例创建的检测与装饰的添加。

技巧
print("函数的名称：", func.__name__)
print("函数所属类名", func.__qualname__.split('.')[0])
print("父类元组", cls.__bases__)
"""


def mustcall(func):
    if not hasattr(mustcall, "classname2fun"):
        setattr(mustcall, "classname2fun", dict())  # Parent.func -> <Parent.func object at ...>
        setattr(mustcall, "classnames", list())  # 注册的类名

    classname2fun = getattr(mustcall, "classname2fun")
    classnames = getattr(mustcall, "classnames")
    classnames.append(func.__qualname__.split('.')[0])
    classname2fun[func.__qualname__] = func  # Parent.func -> <Parent.func object at ...>

    return func


class MustCall:
    def __new__(cls, *args, **kwargs):
        if cls.__name__ != __class__.__name__:  # 检测到 MustCall的子类
            if cls.__name__ not in getattr(mustcall, "classnames"):  # 检测到 集成MustCAll基类的类的子类
                # 获取父类的名称，即父类的父类含有MustCall
                baseclassname = None
                for base in cls.__bases__:
                    if any(base_.__name__ == __class__.__name__ for base_ in base.__bases__):
                        baseclassname = base.__name__
                # 对子类进行方法封装
                for classname, func in getattr(mustcall, "classname2fun").items():
                    if classname.split(".")[0] == baseclassname:
                        subfunc = getattr(cls, func.__name__)

                        def newfunc(self, *args, **kw):
                            func(self, *args, **kw)
                            subfunc(self, *args, **kw)

                        setattr(cls, func.__name__, newfunc)

        return super().__new__(cls)
